package org.dromara.common.core.utils.tree;

import org.springframework.util.Assert;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;

public class TreeListBuildUtil<T> {

    private final Field idField;          // ID字段
    private final Field parentIdField;    // 父节点ID字段
    private final Field childrenField;    // 子节点列表字段

    /**
     * 构造函数，初始化TreeListUtil对象。
     *
     * @param classType 要操作的数据类的Class对象。
     */
    public TreeListBuildUtil(Class<T> classType) {
        // 获取并设置ID字段、父节点ID字段和子节点列表字段
        this.idField = getFieldWithTreeCruxAnnotation(classType, TreeCruxEnum.ID);
        this.parentIdField = getFieldWithTreeCruxAnnotation(classType, TreeCruxEnum.PID);
        this.childrenField = getFieldWithTreeCruxAnnotation(classType, TreeCruxEnum.CHILD_LIST);
    }

    /**
     * 根据注解值获取带有TreeCruxField注解的字段。
     *
     * @param clazz           数据类的Class对象。
     * @param annotationValue 注解值（ID、父节点ID或子节点列表）。
     * @return 带有指定注解的字段。
     */
    private Field getFieldWithTreeCruxAnnotation(Class<T> clazz, TreeCruxEnum annotationValue) {
        List<Field> annotatedFields = new ArrayList<>();
        for (Field field : clazz.getDeclaredFields()) {
            TreeCruxField annotation = field.getAnnotation(TreeCruxField.class);
            if (annotation != null && annotation.value() == annotationValue) {
                annotatedFields.add(field);
            }
        }
        Assert.isTrue(annotatedFields.size() == 1,
            String.format("class %s TreeCruxField value is more than one attribute for %s ", clazz.getName(), annotationValue));
        Field field = annotatedFields.get(0);
        field.setAccessible(true);  // 设置字段访问权限为可访问
        return field;
    }

    /**
     * 构建树状结构。
     *
     * @param dataList 包含数据的列表。
     * @return 树状结构的根节点列表。
     */
    public List<T> buildTree(List<T> dataList) {
        List<T> treeList = new ArrayList<>();
        dataList.stream()
            .filter(obj -> {
                try {
                    // 过滤出根节点
                    return 0 == (Integer) parentIdField.get(obj);
                } catch (IllegalAccessException e) {
                    throw new RuntimeException("The parent ID field is not of type Long", e);
                }
            })
            .peek(treeList::add)
            .forEach(root -> addChildren(root, dataList));

        return treeList;
    }

    /**
     * 递归添加子节点。
     *
     * @param parent     父节点。
     * @param dataList   包含数据的列表。
     */
    private void addChildren(T parent, List<T> dataList) {
        dataList.stream()
            .filter(data -> {
                try {
                    // 查找与父节点ID匹配的子节点
                    return parentIdField.get(data).equals(idField.get(parent));
                } catch (IllegalAccessException e) {
                    throw new RuntimeException("The ID and parent ID field types are different", e);
                }
            })
            .peek(child -> {
                try {
                    // 添加子节点到父节点的子节点列表
                    List<T> childList = (List<T>) childrenField.get(parent);
                    if (childList == null) {
                        childList = new ArrayList<>();
                        childrenField.set(parent, childList);
                    }
                    childList.add(child);
                } catch (IllegalAccessException e) {
                    throw new RuntimeException("Error accessing child list field", e);
                }
            })
            .forEach(child -> addChildren(child, dataList));
    }
}

